package org.dicr.event;

import java.awt.*;
import java.io.*;
import java.util.*;

import javax.swing.*;

/***********************************************************************************************************************
 * @author Igor A Tarasov
 * @version 030122
 **********************************************************************************************************************/
public class DicrExceptionHandler {
	protected static DicrExceptionHandler dicrHandler = null;

	protected Vector<ExceptionListener> listeners = new Vector<ExceptionListener>();

	protected boolean shownAll = false;

	protected boolean logToFile = true;

	protected File logFile = null;

	protected long maxFileSize = 1000000;

	/*******************************************************************************************************************
     * Конструктор
     ******************************************************************************************************************/
	protected DicrExceptionHandler() {
	// NOP
	}

	/*******************************************************************************************************************
     * Возвращает обработчик исключений
     ******************************************************************************************************************/
	public static DicrExceptionHandler getDicrExceptionHandler() {
		if (dicrHandler == null) dicrHandler = new DicrExceptionHandler();
		return dicrHandler;
	}

	/*******************************************************************************************************************
     * Добавляет слушателя исключений
     ******************************************************************************************************************/
	public void addExceptionListener(ExceptionListener l) {
		if (l == null) throw new IllegalArgumentException("null параметр l");
		if (!this.listeners.contains(l)) this.listeners.add(l);
	}

	/*******************************************************************************************************************
     * Удаляет слушателя исключений
     ******************************************************************************************************************/
	public void removeExceptionListener(ExceptionListener l) {
		if (l == null) throw new IllegalArgumentException("null параметр l");
		this.listeners.remove(l);
	}

	/*******************************************************************************************************************
     * Оповещает слушателей
     ******************************************************************************************************************/
	protected void fireException(Throwable th, Object src, boolean shown) {
		for (int i = 0; i < this.listeners.size(); i++)
			try {
				this.listeners.get(i).processException(th, src, shown);
			} catch (Throwable ex) {
				ex.printStackTrace();
			}
	}

	/*******************************************************************************************************************
     * Установка флага безусловного показа исключений
     ******************************************************************************************************************/
	public void setShownAll(boolean shown) {
		this.shownAll = shown;
	}

	/*******************************************************************************************************************
     * Возвращает флаг показа всех сообщений
     ******************************************************************************************************************/
	public boolean getShownAll() {
		return this.shownAll;
	}

	/*******************************************************************************************************************
     * Устанавливает файл лога. Если logFile установлен в null, то вывод сообщений в лог не выполняется.
     ******************************************************************************************************************/
	public void setLogFile(File file) {
		this.logFile = file;
	}

	/*******************************************************************************************************************
     * Возвращает лог-файл
     ******************************************************************************************************************/
	public File getLogFile() {
		return this.logFile;
	}

	/*******************************************************************************************************************
     * Устанавливает максимальный размер лога
     ******************************************************************************************************************/
	public void setMaxFileSize(long maxSize) {
		this.maxFileSize = maxSize;
	}

	/*******************************************************************************************************************
     * Возвращает максимальный размер лога
     ******************************************************************************************************************/
	public long getMaxFileSize() {
		return this.maxFileSize;
	}

	/*******************************************************************************************************************
     * Обрабатывает исключение
     ******************************************************************************************************************/
	public void processException(final Throwable th, final Object src, boolean shown) {
		if (th == null) throw new IllegalArgumentException("null параметр th");
		// выводим на консоль
		try {
			System.err.println("---------- DicrExceptionHandler " + new Date().toString());
			if (src != null) System.err.println("---------- Src: " + src.toString());
			if (this.logFile != null) System.err.println("---------- log-file: " + this.logFile.getPath());
			th.printStackTrace();
		} catch (Throwable thr) {
			thr.printStackTrace();
		}
		// выводим в логи
		PrintStream ou = null;
		if (this.logFile != null) try {
			boolean append = (!this.logFile.exists() || this.logFile.length() < this.maxFileSize);
			ou = new PrintStream(new FileOutputStream(this.logFile.getPath(), append));
			ou.println("---------- DicrExceptionHandler " + new Date().toString());
			if (src != null) ou.println("---------- Src: " + src.toString());
			th.printStackTrace(ou);
		} catch (Throwable thr) {
			thr.printStackTrace();
		} finally {
			if (ou != null) ou.close();
		}
		// показать диалог сообщения об ошибке
		if (SwingUtilities.isEventDispatchThread()) {
			try {
				Toolkit.getDefaultToolkit().beep();
				if (shown || this.shownAll) {
					JOptionPane.showMessageDialog(null,
							"<HTML><TABLE width=90% halign=left border=0 cellpadding=0 cellspacing=10>"
									+ "<TR><TD><B>Исключение:</B></TD><TD>&nbsp;" + th.getClass().getName()
									+ "</TD></TR>" + "<TR><TD><B>Источник:</B></TD><TD>&nbsp;"
									+ (src != null ? src.toString() : "(null)") + "</TD></TR>"
									+ "<TR><TD><B>Текст:</B></TD><TD>&nbsp;" + th.getLocalizedMessage() + "</TD></TR>"
									+ "</TABLE><HTML>", "Ошибка !!!", JOptionPane.ERROR_MESSAGE);
				}
			} catch (Throwable thr) {
				thr.printStackTrace();
			}
		}
	}

	/*******************************************************************************************************************
     * Обработка исключений с оповещением слушателей.
     * 
     * @param ex исключение
     * @param src источник
     * @param shown показывать пользователю
     ******************************************************************************************************************/
	public static void handleException(Throwable ex, Object src, boolean shown) {
		// обрабатываем исключение
		DicrExceptionHandler handler = DicrExceptionHandler.getDicrExceptionHandler();
		try {
			handler.processException(ex, src, shown);
		} catch (Throwable th) {
			th.printStackTrace();
		}
		// оповещаем слушателей
		handler.fireException(ex, src, shown);
	}

	/*******************************************************************************************************************
     * Обработка исключений с оповещением слушателей.
     * 
     * @param ex исключение
     * @param src источник
     ******************************************************************************************************************/
	public static void handleException(Throwable ex, Object src) {
		handleException(ex, src, false);
	}
}
